package netTracker;

import java.io.*;
import javax.sound.midi.*;
import javax.sound.sampled.*;

/**
 * An engine for playing back notes.
 * @author David Cummings
 *
 */
public class PlaybackEngine {
	
	//private static final int	EXTERNAL_BUFFER_SIZE = 128000;

	/** Utility class with debug flag: */
	Util util = new Util(this, true);

	Synthesizer synth;
	MidiChannel channel;
	int lastNote;
	Clip clip;
	AudioFormat format; 


	public void playNote(Cell cell) {
		Note n = cell.getNote();
		if(n.getFrequency()!= Note.EMPTY){
			long legatoDuration = 500;
			stopNote(legatoDuration);
			if(n.getFrequency() != Note.CUTOFF)
				new Thread(new WavePlayer("sounds/shakuhachi.wav", n.getFrequency())).start();
		}
	}
	
	public void stopNote(long legatoDuration){
		if(clip!=null)
			new Thread(new StopNoteThread(legatoDuration)).start();
	}
	
	public void shutdownEngine(){
		synth.close();
	}
	
	/**
	 * An internal class for playing back wave files. 
	 * Plays back a given file at a given frequency.
	 * @author David Cummings
	 *
	 */
	class WavePlayer implements Runnable{
		String filename;
		Double frequency;
		public WavePlayer(String filename, Double frequency){
			this.filename=filename;
			this.frequency=frequency;
		}
		
		public void run(){
			try{
				/*
				Mixer.Info[] myInfo = AudioSystem.getMixerInfo();
				for(int i=0; i<myInfo.length; i++){
					System.out.println(myInfo[i]);
				} // TODO have user choose correct sound engine.
				  // Also does not work on linux --no sample rate control support. */
		
				Object currentSound = AudioSystem.getAudioInputStream(new File(filename));
				AudioInputStream stream = (AudioInputStream) currentSound;
				format = stream.getFormat();
	
				clip = AudioSystem.getClip(AudioSystem.getMixerInfo()[4]);	// Get the line from the mixer.
				currentSound = clip;
				clip.open(stream);
				
				/** Set the frequency of the clip by getting a control for the sample rate: */
				FloatControl rateControl = (FloatControl) clip.getControl(FloatControl.Type.SAMPLE_RATE);
				float newRate = format.getSampleRate() * (float)(frequency / 250);
				rateControl.setValue(newRate);					
				clip.start();
			}catch(Exception x){
				util.debug(x);
			}
		}
	}
	
	/**
	 * An internal class for stopping a note. Waits before stopping the note to allow legato.
	 * @author David Cummings
	 */
	class StopNoteThread implements Runnable {
		long legatoDuration;
		public StopNoteThread(long legatoDuration){
			this.legatoDuration=legatoDuration;
		}
		public void run() {
			try{
				Thread.sleep(legatoDuration);
			}catch(InterruptedException x){
				util.debug(x);
			}
			clip.stop();
		}
	}

}
